package com.hmall.common.domain;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.common.utils.BeanUtils;
import com.hmall.common.utils.CollUtils;
import com.hmall.common.utils.Convert;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 分页数据传输对象
 * 用于封装分页查询结果，包含总记录数、总页数和当前页数据
 * @param <T> 分页数据的元素类型
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageDTO<T> {

    /**
     * 总记录数
     */
    protected Long total;

    /**
     * 总页数
     */
    protected Long pages;

    /**
     * 当前页数据列表
     */
    protected List<T> list;

    /**
     * 创建空分页对象（自定义总记录数和总页数）
     * @param total 总记录数
     * @param pages 总页数
     * @param <T> 元素类型
     * @return 空数据的分页对象
     */
    public static <T> PageDTO<T> empty(Long total, Long pages) {
        return new PageDTO<>(total, pages, CollUtils.emptyList());
    }

    /**
     * 基于MyBatis-Plus的Page对象创建空分页对象
     * @param page MyBatis-Plus分页对象
     * @param <T> 元素类型
     * @return 空数据的分页对象
     */
    public static <T> PageDTO<T> empty(Page<?> page) {
        return new PageDTO<>(page.getTotal(), page.getPages(), CollUtils.emptyList());
    }

    /**
     * 直接将MyBatis-Plus的Page对象转换为PageDTO
     * @param page MyBatis-Plus分页对象
     * @param <T> 元素类型
     * @return 转换后的分页DTO
     */
    public static <T> PageDTO<T> of(Page<T> page) {
        if(page == null){
            return new PageDTO<>();
        }
        if (CollUtils.isEmpty(page.getRecords())) {
            return empty(page);
        }
        return new PageDTO<>(page.getTotal(), page.getPages(), page.getRecords());
    }

    /**
     * 将MyBatis-Plus的Page对象转换为PageDTO，并通过映射函数转换元素类型
     * @param page MyBatis-Plus分页对象
     * @param mapper 元素映射函数
     * @param <T> 目标元素类型
     * @param <R> 源元素类型
     * @return 转换后的分页DTO
     */
    public static <T,R> PageDTO<T> of(Page<R> page, Function<R, T> mapper) {
        if(page == null){
            return new PageDTO<>();
        }
        if (CollUtils.isEmpty(page.getRecords())) {
            return empty(page);
        }
        return new PageDTO<>(page.getTotal(), page.getPages(),
                page.getRecords().stream().map(mapper).collect(Collectors.toList()));
    }

    /**
     * 基于MyBatis-Plus的Page对象和自定义数据列表创建PageDTO
     * @param page MyBatis-Plus分页对象（提供分页信息）
     * @param list 自定义数据列表
     * @param <T> 元素类型
     * @return 转换后的分页DTO
     */
    public static <T> PageDTO<T> of(Page<?> page, List<T> list) {
        return new PageDTO<>(page.getTotal(), page.getPages(), list);
    }

    /**
     * 将MyBatis-Plus的Page对象转换为PageDTO，并通过Bean属性复制转换元素类型
     * @param page MyBatis-Plus分页对象
     * @param clazz 目标元素类型的Class
     * @param <T> 目标元素类型
     * @param <R> 源元素类型
     * @return 转换后的分页DTO
     */
    public static <T, R> PageDTO<T> of(Page<R> page, Class<T> clazz) {
        return new PageDTO<>(page.getTotal(), page.getPages(), BeanUtils.copyList(page.getRecords(), clazz));
    }

    /**
     * 将MyBatis-Plus的Page对象转换为PageDTO，并通过自定义转换器转换元素类型
     * @param page MyBatis-Plus分页对象
     * @param clazz 目标元素类型的Class
     * @param convert 自定义转换器
     * @param <T> 目标元素类型
     * @param <R> 源元素类型
     * @return 转换后的分页DTO
     */
    public static <T, R> PageDTO<T> of(Page<R> page, Class<T> clazz, Convert<R, T> convert) {
        return new PageDTO<>(page.getTotal(), page.getPages(), BeanUtils.copyList(page.getRecords(), clazz, convert));
    }
}